package collection;

import exception.CollectionEmptyException;
import exception.CollectionFullException;

public class ArrayQueue<E> implements IQueue<E>{

	public static final int DEFAULT_CAPACITY = 10;
	private E[] internalArray;
	int headIndex;
	int tailIndex;
	int size;

	public ArrayQueue()
	{
		this.internalArray = (E[]) new Object[DEFAULT_CAPACITY];
		this.headIndex = 0;
		this.tailIndex = 0;
		this.size = 0;
	}
	
	public ArrayQueue(int capacity)
	{
		this.internalArray = (E[]) new Object[capacity];
		this.headIndex = 0;
		this.tailIndex = 0;
		this.size = 0;
	}
	
	@Override
	public boolean isEmpty() 
	{
		return this.size == 0;
	}
	
	private boolean isFull()
	{
		return this.size == this.internalArray.length;
	}
	
	@Override
	public int size() 
	{
		return this.size;
	}
	@Override
	public void enqueue(E element) 
	{
		if (isEmpty())
		{
			this.internalArray[this.tailIndex] = element;
			this.size += 1;
		}
		else if(isFull())
		{
			throw new CollectionFullException("Queue");
		}
		else
		{
			this.tailIndex = (this.tailIndex + 1) % this.internalArray.length;
			this.internalArray[this.tailIndex] = element;
			this.size += 1;
		}
	}
	@Override
	public E dequeue() throws CollectionEmptyException 
	{
		if (isEmpty())
		{
			throw new CollectionEmptyException("Queue");
		}
		else if (this.headIndex == this.tailIndex)
		{
			E retVal = this.internalArray[this.headIndex];
			this.size -= 1;
			
			return retVal;
		}
		else
		{
			E retVal = this.internalArray[this.headIndex];
			this.headIndex = (this.headIndex + 1) % this.internalArray.length;
			this.size -= 1;
			
			return retVal;
		}
	}
	@Override
	public E front() throws CollectionEmptyException 
	{
		if (isEmpty())
		{
			throw new CollectionEmptyException("Queue");
		}
		else
		{
			return this.internalArray[this.headIndex];
		}
	}
	
	@Override
	public String toString()
	{
		if (isEmpty())
			return "[]";
		else
		{
			String retStr = "[ ";
			int index = this.headIndex;
			for (int i = 0; i<this.size; i++)
			{
				if (i == this.size - 1)
				{
					retStr += this.internalArray[index];
				}
				else
				{
					retStr += this.internalArray[index] + ", ";
				}
				index = (index + 1) % this.internalArray.length;
			}
			retStr += " ]";
			
			return retStr;
		}
	}
	
}
